/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with this
 * work for additional information regarding copyright ownership. The ASF
 * licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.apache.openjpa.persistence.test;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;

/**
 * A base test case that can be used to easily test scenarios where there is
 * only a single EntityManager at any given time.
 * 
 * @author Marc Prud'hommeaux
 */
public abstract class SingleEMTestCase extends SingleEMFTestCase {

  protected EntityManager em;

  @Override
  public void setUp() {
    setUp(new Object[0]);
  }

  @Override
  public void setUp(Object... props) {
    super.setUp(props);
    em = emf.createEntityManager();
  }

  /**
   * Clear the current EntityManager and re-initialize it.
   */
  protected void reset() {
    close();
    em = emf.createEntityManager();
  }

  @Override
  public void tearDown() throws Exception {
    rollback();
    close();
    super.tearDown();
  }

  /**
   * Start a new transaction if there isn't currently one active.
   * 
   * @return true if a transaction was started, false if one already existed
   */
  protected boolean begin() {
    EntityTransaction tx = em.getTransaction();
    if (tx.isActive())
      return false;

    tx.begin();
    return true;
  }

  /**
   * Commit the current transaction, if it is active.
   * 
   * @return true if the transaction was committed
   */
  protected boolean commit() {
    EntityTransaction tx = em.getTransaction();
    if (!tx.isActive())
      return false;

    tx.commit();
    return true;
  }

  /**
   * Rollback the current transaction, if it is active.
   * 
   * @return true if the transaction was rolled back
   */
  protected boolean rollback() {
    if (null != em) {
      EntityTransaction tx = em.getTransaction();
      if (!tx.isActive())
        return false;

      tx.rollback();
    }
    return true;
  }

  /**
   * Closes the current EntityManager if it is open.
   * 
   * @return false if the EntityManager was already closed.
   */
  protected boolean close() {
    if (em == null)
      return false;

    rollback();

    if (!em.isOpen())
      return false;

    em.close();
    return !em.isOpen();
  }

  /**
   * Delete all of the instances.
   * 
   * If no transaction is running, then one will be started and committed.
   * Otherwise, the operation will take place in the current transaction.
   */
  protected void remove(Object... obs) {
    boolean tx = begin();
    for (Object ob : obs)
      em.remove(ob);
    if (tx)
      commit();
  }

  /**
   * Persist all of the instances.
   * 
   * If no transaction is running, then one will be started and committed.
   * Otherwise, the operation will take place in the current transaction.
   */
  protected void persist(Object... obs) {
    boolean tx = begin();
    for (Object ob : obs)
      em.persist(ob);
    if (tx)
      commit();
  }

  protected abstract String getPersistenceUnitName();
}
